package com.summer.filesync.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.summer.filesync.util.Logger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

/** JWT令牌工具类 提供JWT的生成、验证和解析功能 */
public class JwtUtil {
  private static final Logger logger = Logger.getLogger(JwtUtil.class);

  // JWT密钥 - 在生产环境中应该从配置文件或环境变量读取
  private static final String SECRET_KEY =
      "distributed-file-sync-2025-secret-key-change-in-production";

  // 令牌有效期（小时）
  private static final int TOKEN_VALIDITY_HOURS = 24;

  private static final ObjectMapper objectMapper = new ObjectMapper();

  /**
   * 生成JWT令牌
   *
   * @param username 用户名
   * @param role 用户角色
   * @return JWT令牌
   */
  public static String generateToken(String username, UserRole role) {
    try {
      // 创建Header
      Map<String, Object> header = new HashMap<>();
      header.put("alg", "HS256");
      header.put("typ", "JWT");

      // 创建Payload
      Map<String, Object> payload = new HashMap<>();
      payload.put("sub", username);
      payload.put("role", role.name());
      payload.put("iat", LocalDateTime.now().toEpochSecond(ZoneOffset.UTC));
      payload.put(
          "exp", LocalDateTime.now().plusHours(TOKEN_VALIDITY_HOURS).toEpochSecond(ZoneOffset.UTC));
      payload.put("iss", "distributed-file-sync");

      // Base64编码Header和Payload
      String encodedHeader = base64UrlEncode(objectMapper.writeValueAsString(header));
      String encodedPayload = base64UrlEncode(objectMapper.writeValueAsString(payload));

      // 创建签名
      String signature = createSignature(encodedHeader + "." + encodedPayload);

      return encodedHeader + "." + encodedPayload + "." + signature;

    } catch (Exception e) {
      logger.error("Failed to generate JWT token", e);
      return null;
    }
  }

  /**
   * 验证JWT令牌
   *
   * @param token JWT令牌
   * @return 验证结果
   */
  public static TokenValidationResult validateToken(String token) {
    try {
      if (token == null || token.trim().isEmpty()) {
        return TokenValidationResult.invalid("Token is empty");
      }

      String[] parts = token.split("\\.");
      if (parts.length != 3) {
        return TokenValidationResult.invalid("Invalid token format");
      }

      String header = parts[0];
      String payload = parts[1];
      String signature = parts[2];

      // 验证签名
      String expectedSignature = createSignature(header + "." + payload);
      if (!signature.equals(expectedSignature)) {
        return TokenValidationResult.invalid("Invalid signature");
      }

      // 解析Payload
      String payloadJson = base64UrlDecode(payload);
      @SuppressWarnings("unchecked")
      Map<String, Object> claims = objectMapper.readValue(payloadJson, Map.class);

      // 检查过期时间
      Number expNumber = (Number) claims.get("exp");
      if (expNumber == null) {
        return TokenValidationResult.invalid("Missing expiration time");
      }

      long exp = expNumber.longValue();
      long currentTime = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC);

      if (currentTime > exp) {
        return TokenValidationResult.invalid("Token expired");
      }

      // 提取用户信息
      String username = (String) claims.get("sub");
      String roleStr = (String) claims.get("role");
      UserRole role = UserRole.valueOf(roleStr);

      return TokenValidationResult.valid(username, role, claims);

    } catch (Exception e) {
      logger.error("Failed to validate JWT token", e);
      return TokenValidationResult.invalid("Token validation error: " + e.getMessage());
    }
  }

  /** 创建HMAC-SHA256签名 */
  private static String createSignature(String data) {
    try {
      Mac mac = Mac.getInstance("HmacSHA256");
      SecretKeySpec secretKeySpec =
          new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
      mac.init(secretKeySpec);
      byte[] hash = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
      return base64UrlEncode(hash);
    } catch (Exception e) {
      throw new RuntimeException("Failed to create signature", e);
    }
  }

  /** Base64 URL安全编码 */
  private static String base64UrlEncode(String data) {
    return base64UrlEncode(data.getBytes(StandardCharsets.UTF_8));
  }

  private static String base64UrlEncode(byte[] data) {
    return Base64.getUrlEncoder().withoutPadding().encodeToString(data);
  }

  /** Base64 URL安全解码 */
  private static String base64UrlDecode(String data) {
    byte[] decoded = Base64.getUrlDecoder().decode(data);
    return new String(decoded, StandardCharsets.UTF_8);
  }

  /** 生成API密钥 */
  public static String generateApiKey() {
    SecureRandom random = new SecureRandom();
    byte[] bytes = new byte[32];
    random.nextBytes(bytes);
    return Base64.getEncoder().encodeToString(bytes);
  }

  /** 生成密码哈希 */
  public static String hashPassword(String password, String salt) {
    try {
      MessageDigest md = MessageDigest.getInstance("SHA-256");
      md.update(salt.getBytes(StandardCharsets.UTF_8));
      byte[] hashedPassword = md.digest(password.getBytes(StandardCharsets.UTF_8));
      return Base64.getEncoder().encodeToString(hashedPassword);
    } catch (NoSuchAlgorithmException e) {
      throw new RuntimeException("SHA-256 algorithm not available", e);
    }
  }

  /** 生成随机盐值 */
  public static String generateSalt() {
    SecureRandom random = new SecureRandom();
    byte[] salt = new byte[16];
    random.nextBytes(salt);
    return Base64.getEncoder().encodeToString(salt);
  }
}
